---
title: .autoDispose
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";

통상적으로 프로바이더를 사용할때, 프로바이더를 더이상 사용하지 않는다면 
시스템 메모리상에서 해제(destroy)하고 싶은 경우가 있습니다. 

destroy하고 싶은 경우는 다양한 이유가 있지만 아래의 경우를 생각해볼 수 있습니다. 

- 파이어베이스(Firebase)를 사용할떄  불필요한 코스트 발생을 피하기 위해 연결을 끊는 경우
- 사용자가 화면상에서 떠나고 재진입했을때 상태를 초기화 해줘야 하는 경우

위의 경우등을 대응할 수 있도록 프로바이더는 빌트인으로 `.autoDispose` 수식어를 지원합니다. 

## 사용방법

Riverpod에 더이상 사용하지 않는 프로바이더의 상태를 소멸(destroy)하기위해 
`.autoDispose` 수식어를 프로바이더에 붙이기만 하면 됩니다. 


```dart
final userProvider = StreamProvider.autoDispose<User>((ref) {

});
```

이것으로 `userProvider`가 더 이상 사용되지 않을때 자동으로 해제 작업을 처리합니다.

제네릭 파라미터가  `autoDispose`전에 붙는게 아닌 `autoDispose`뒤에 붙는 것으로 
알 수 있듯이  `autoDispose`는 a named constructor가 아닙니다.

:::note
`.autoDispose`와 다른 수식어를 결합할 수 있습니다. 


```dart
final userProvider = StreamProvider.autoDispose.family<User, String>((ref, id) {

});
```

:::

### ref.keepAlive

프로바이더에 `autoDispose` 수식어를 붙이면 `ref`객체에 `keepAlive` 메소드를 사용할 수 있습니다. 

`keepAlive` 메소드를 실행하는 것으로, 프로바이더가 참조되지 않게 되었을 때에도 
상태를 유지하도록 Riverpod 에 전할 수가 있습니다.

좀 더 이해를 돕기위해서 HTTP 요청이 완료되면 플레그를 `true`로 설정하는 예시 코드입니다. 

```dart
final myProvider = FutureProvider.autoDispose((ref) async {
  final response = await httpClient.get(...);
  ref.keepAlive();
  return response;
});
```

위의 방식을 사용하면, 만약에 요청이 실패하고 사용자가 화면상에서 떠나고 다시 들어온 경우
요청을 재 실행할 수 있도록 합니다. 그러나, 만약 요청이 성공적으로 처리된다면, 상태가 유지될 것입니다. 
그리고 화면에 재 진입해도 새로운 요청을 위한 트리거링이 발생하지 않습니다. 


## 사용예: 더 이상 프로바이더를 사용하지 않을 때, HTTP 요청 취소하기

`autoDispose` 수식어는  [FutureProvider]와  `ref.onDispose`에 결합 할 수 있습니다.
프로바이더를 더 이상 사용하지 않을 때 쉽게 HTTP 요청을 취소할 수 있습니다. 

이번 예시의 목표는 다음과 같습니다. 

- 사용자가 화면에 들어왔을 때 HTTP 요청을 시작합니다.
- 만약 요청이 완료되기 전에 사용자가 화면을 떠났다면, HTTP을 취소합니다.
- 만약 요청이 성공했다면, 화면을 떠나거나 재 진입했을때 새로운 요청을 시작하지 않습니다. 

코드로 구현해 본다면 아래와 같습니다. 

```dart
final myProvider = FutureProvider.autoDispose((ref) async {
  // http 요청을 취소하기 위한 package:dio 객체 
  final cancelToken = CancelToken();
  // 프로바이더가 해제(destroyed)될 때, http 요청을 취소합니다.
  ref.onDispose(() => cancelToken.cancel());

  // 데이터를 가져오고 취소하기 위한 `cancelToken`을 파라미터로 념겨줍니다. 
  final response = await dio.get('path', cancelToken: cancelToken);
  // 만약 요청이 성곡적으로 완료되었다면, 현재 상태를 유지합니다. 
  ref.keepAlive();
  return response;
});
```

## 'AutoDisposeProvider'인수 타입은 'AlwaysAliveProviderBase' 매개변수에 할당할 수 없습니다.

`.autoDispose`를 사용할 때, 아래와 같은 에러가 발생하면서 컴파일이 되지 않는 경우를 
만나볼 수 있습니다. 

> The argument type 'AutoDisposeProvider' can't be assigned to the parameter
> type 'AlwaysAliveProviderBase'

걱정 하지 마세요! 이 에러는 자발적으로 발생하는 오류입니다.
버그가 발생할 가능성이 높기 때문에 발생하는 오류입니다. 

`.autoDispose`의 수식어를 붙이지 않은 프로바이더에서 `.autoDispose` 수식어를 사용한 
프로바이더를 사용할 경우 발생할 수 있습니다. 


```dart
final firstProvider = Provider.autoDispose((ref) => 0);

final secondProvider = Provider((ref) {
  // 'AutoDisposeProvider<int>'인자 값을
  // 'AlwaysAliveProviderBase<Object, Null>' 파라미터 타입으로 할당할 수 없습니다. 
  ref.watch(firstProvider);
});
```

위의 코드의 경우 `firstProvider`가 절대 disposed 처리 않음으로 사용상 바람직하지 않습니다. 

이를 수정하기 위해 `secondProvider`에 `.autoDispose`를 추가할 필요가 있습니다. 

```dart
final firstProvider = Provider.autoDispose((ref) => 0);

final secondProvider = Provider.autoDispose((ref) {
  ref.watch(firstProvider);
});
```

[futureprovider]: ../../providers/future_provider
